package com.sinog.core.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * @desc 用户登录密码传递加密，后台解密
 * @author dh
 * @date 2020-04-09-14:01
 */
@Slf4j
public final class AesUtil {

    /**
     * 生成AES秘钥，然后Base64编码
     * @return String
     */
    public static String genKeyAes() throws java.security.NoSuchAlgorithmException {
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(128);
        SecretKey key = keyGen.generateKey();
        return byte2Base64(key.getEncoded());
    }

    /**
     * 将Base64编码后的AES秘钥转换成SecretKey对象
     * @param base64Key base64Key
     * @return SecretKey
     */
    public static SecretKey loadKeyAes(String base64Key) throws IOException {
        byte[] bytes = base642Byte(base64Key);
        return new SecretKeySpec(bytes,"AES");
    }

    /**
     * 字节数组转Base64编码
     * @param bytes bytes
     * @return String
     */
    public static String byte2Base64(byte[] bytes) {
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(bytes);
    }

    /**
     * Base64编码转字节数组
     * @param base64Key base64Key
     * @return byte[]
     */
    public static byte[] base642Byte(String base64Key) throws IOException {
        BASE64Decoder decoder = new BASE64Decoder();
        return decoder.decodeBuffer(base64Key);
    }

    /**
     * 加密
     * @param source source
     * @param key key
     * @return byte[]
     */
    public static byte[] encryptAes(byte[] source,SecretKey key) {
        Cipher cipher;
        try {
            cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE,key);
            return cipher.doFinal(source);
        } catch(NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
            log.error(e.getMessage());
            return null;
        }
    }

    /**
     * 解密
     * @param source source
     * @param key key
     * @return byte[]
     */
    public static byte[] decryptAes(byte[] source,SecretKey key) {
        Cipher cipher;
        try {
            cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.DECRYPT_MODE,key);
            return cipher.doFinal(source);
        } catch(NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
            log.error(e.getMessage());
            return null;
        }
    }

    /**
     * 字节码转字符串
     * @param byte1 byte1
     * @return String
     */
    public static String byteToString(byte[] byte1) {
        return new String(byte1);
    }

    /**
     * 加密
     * @param content content
     * @param keyBytes keyBytes
     * @param iv iv
     * @return byte[]
     */
    public static byte[] aesCbcEncrypt(byte[] content,byte[] keyBytes,byte[] iv) {
        try {
            SecretKeySpec key = new SecretKeySpec(keyBytes,"AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE,key,new IvParameterSpec(iv));
            return cipher.doFinal(content);
        } catch(InvalidAlgorithmParameterException | InvalidKeyException | NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException e) {
            log.error("exception:",e);
        }
        return null;
    }

    /**
     * 解密
     * @param content content
     * @param keyBytes keyBytes
     * @param iv iv
     * @return byte[]
     */
    public static byte[] aesCbcDecrypt(byte[] content,byte[] keyBytes,byte[] iv) {
        try {
            SecretKeySpec key = new SecretKeySpec(keyBytes,"AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE,key,new IvParameterSpec(iv));
            return cipher.doFinal(content);
        } catch(InvalidAlgorithmParameterException | InvalidKeyException | NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException e) {
            log.error("exception:{}",e.getMessage());
        }
        return null;
    }

    /**
     * 字符串装换成base64
     * @param key key
     * @return byte[]
     */
    public static byte[] decryptBase64(String key) {
        return Base64.decodeBase64(key.getBytes());
    }

    /**
     * base64装换成字符串
     * @param key key
     * @return String
     */
    public static String encryptBase64(byte[] key) {
        return new String(Base64.encodeBase64(key));
    }
}